#ifndef __M_ROUTE_H__
#define __M_ROUTE_H__
#include "../mqcommon/helper.hpp"
#include "../mqcommon/log.hpp"
#include "../mqcommon/mq_meg.pb.h"

namespace pprmq
{
    class Route
    {
    public:
        static bool isLegalRoutingKey(const std::string& routing_key)
        {
            // routing_key：只需要判断是否包含有非法字符即可， 合法字符( a~z, A~Z, 0~9, ., _)
            for(auto& c : routing_key)
            {
                if( (c >= 'a' && c <= 'z') || 
                    (c >= 'A' && c <= 'Z') || 
                    (c >= '0' && c <= '9') || 
                    (c == '.' || c == '_'))
                {
                    continue;
                }
                return false;
            }
            return true;
        }
        static bool isLegalBindingKey(const std::string& binding_key)
        {
            // 1. 判断是否包含有非法字符， 合法字符：a~z, A~Z, 0~9, ., _, *, #
            for(auto& c : binding_key)
            {
                if( (c >= 'a' && c <= 'z') || 
                    (c >= 'A' && c <= 'Z') || 
                    (c >= '0' && c <= '9') || 
                    (c == '.' || c == '_') ||
                    (c == '*' || c == '#'))
                {
                    continue;
                }
                return false;
            }
            // 2. *和#必须独立存在:  news.music#.*.#
            std::vector<std::string> result;
            StrHelper::split(binding_key,".",result);
            for(auto& word : result)
            {
                if( word.size() > 1 &&
                    (word.find("*") != std::string::npos || 
                    word.find("#") != std::string::npos))
                {
                    // 找到了,是不合法的
                    return false;
                }
            }
            // 3. #前后 不能连续其他通配符
            for(int i = 1;i<result.size();i++)
            {
                if(result[i] == "#" && result[i-1] == "*") return false;
                if(result[i] == "#" && result[i-1] == "#") return false;
                if(result[i] == "*" && result[i-1] == "#") return false;
            }
            return true;
        }

        // binding_key是队列的，routing_key是消息的
        static bool route(ExchangeType type, const std::string &routing_key, const std::string &binding_key)
        {
            if(type == ExchangeType::DIRECT)
            {
                return (routing_key == binding_key);
            }
            else if(type == ExchangeType::FANOUT)
            {
                return true;
            }
            std::vector<std::string> rkeys,bkeys;
            // 主题交换：要进行模式匹配    news.#   &   news.music.pop
            // 1. 将binding_key与routing_key进行字符串分割，得到各个的单词数组            
            int n_rkey = StrHelper::split(routing_key,".",rkeys);
            int n_bkey = StrHelper::split(binding_key,".",bkeys);
            // 2. 定义标记数组，并初始化[0][0]位置为true，其他位置为false
            std::vector<std::vector<bool>> dp(n_bkey+1,std::vector<bool>(n_rkey+1,false));
            dp[0][0] = true;
            // 3. 如果binding_key以#起始，则将#对应行的第0列置为true
            for(int i = 1;i<=bkeys.size();i++)
            {
                if(bkeys[i-1] == "#")
                {
                    dp[i][0] = true;
                    continue;
                }
                break;
            }
            // 4. 使用routing_key中的每个单词与binding_key中的每个单词进行匹配并标记数组
            for(int i = 1;i<=n_bkey;i++)
            {
                for(int j = 1;j<=n_rkey;j++)
                {
                    // 如果当前bkey是个*，或者两个单词相同，表示单词匹配成功，则从左上方继承结果
                    if(bkeys[i-1] == "*" || bkeys[i-1] == rkeys[j-1])
                    {
                        dp[i][j] = dp[i-1][j-1];
                    }
                    else if(bkeys[i-1] == "#")
                    {
                        // 如果当前bkey是个#，则需要从左上，左边，上边继承结果
                        dp[i][j] = dp[i-1][j] | dp[i-1][j-1] | dp[i][j-1];
                    }
                }
            }
            return dp[n_bkey][n_rkey];
        }
    };
}


#endif